package org.zjt.platform.springbootreactivedemo.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties;

import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.codec.CodecCustomizer;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.web.reactive.config.WebFluxConfigurer;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.*;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.zjt.platform.springbootreactivedemo.component.PersonHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.zjt.platform.springbootreactivedemo.vo.JsonResult;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.reactive.function.server.RequestPredicates.*;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;

/**
 * @author <a href="juntao.zhang@qq.com">juntao.zhang</a>
 * @Description:
 * @Package org.zjt.platform.springbootreactivedemo.config
 * @date 2018/3/15 10:21
 * @see
 */
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnClass({WebFluxConfigurer.class})
@AutoConfigureBefore({WebFluxAutoConfiguration.class})
@EnableConfigurationProperties({ServerProperties.class, ResourceProperties.class})
public class RoutingConfiguration {

    @Bean
    public RouterFunction<ServerResponse> monoRouterFunction(PersonHandler personHandler) {
        return route(GET("/person/{id}").and(accept(APPLICATION_JSON)), personHandler::getPerson)
                .andRoute(RequestPredicates.POST("/person").and(accept(APPLICATION_JSON)), personHandler::savePerson)
                .andRoute(DELETE("/person/{id}").and(accept(APPLICATION_JSON)), personHandler::deletePerson);
    }


    @Bean
    @Order(-1)
    public CustomErrorWebExceptionHandler customErrorWebExceptionHandler(ServerProperties serverProperties,ObjectProvider<List<ViewResolver>> viewResolversProvider, ErrorAttributes errorAttributes, ResourceProperties resourceProperties, ApplicationContext applicationContext, ServerCodecConfigurer serverCodecConfigurer){
        CustomErrorWebExceptionHandler customErrorWebExceptionHandler = new CustomErrorWebExceptionHandler(errorAttributes,resourceProperties,serverProperties.getError(), applicationContext);
        List<ViewResolver> viewResolvers = viewResolversProvider.getIfAvailable(() -> Collections.emptyList());
        customErrorWebExceptionHandler.setViewResolvers(viewResolvers);
        customErrorWebExceptionHandler.setMessageWriters(serverCodecConfigurer.getWriters());
        customErrorWebExceptionHandler.setMessageReaders(serverCodecConfigurer.getReaders());
        return customErrorWebExceptionHandler;

    }


    @Bean
    public CodecCustomizer customizedCodecCustomizer(){
        return codecConfigurer -> {
            codecConfigurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder());
            codecConfigurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder());
        };
    }

}


